home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Internet Tools 1993 July / Internet Tools.iso / RockRidge / mail / mmdf / mmdf-IIb.43 / uip / ucbmail / collect.c < prev    next >
Encoding:
C/C++ Source or Header  |  1988-03-28  |  17.4 KB  |  951 lines

  1. /*
  2.  *  C O L L E C T . C 
  3.  *  EE/CIS Computer Lab
  4.  *  Department of Computer and Information Sciences
  5.  *  Department of Electrical Engineering
  6.  *  University of Delaware
  7.  *
  8.  *  REVISION HISTORY:
  9.  *
  10.  *  $Revision: 1.5 $
  11.  *
  12.  *  $Log:    collect.c,v $
  13.  * Revision 1.5  86/01/14  14:22:45  galvin
  14.  * Add extract() and detract() calls to parse the lines entered by the
  15.  * user when attempting to add to the To, Cc and Bcc address lists.
  16.  * 
  17.  * Fix addto() to insert commas between addresses.
  18.  * 
  19.  * Revision 1.4  85/12/18  13:20:12  galvin
  20.  * Add another argument to send to indicate whether or not this
  21.  * message should be delimited by MMDF message delimiters.
  22.  * 
  23.  * Revision 1.3  85/11/16  15:18:24  galvin
  24.  * Added define for sigmask for backward compatibility from 4.3bsd to 4.2bsd.
  25.  * 
  26.  * Revision 1.2  85/11/16  14:27:08  galvin
  27.  * Added comment header for revision history.
  28.  * 
  29.  *
  30.  */
  31.  
  32. /*
  33.  * Copyright (c) 1980 Regents of the University of California.
  34.  * All rights reserved.  The Berkeley software License Agreement
  35.  * specifies the terms and conditions for redistribution.
  36.  */
  37.  
  38. #ifndef lint
  39. static char *sccsid = "@(#)collect.c    5.2 (Berkeley) 6/21/85";
  40. #endif not lint
  41.  
  42. /*
  43.  * Mail -- a mail program
  44.  *
  45.  * Collect input from standard input, handling
  46.  * ~ escapes.
  47.  */
  48.  
  49. #include "./rcv.h"
  50. #include <sys/stat.h>
  51. #include "./sigretro.h"
  52.  
  53. /*
  54.  * Read a message from standard output and return a read file to it
  55.  * or NULL on error.
  56.  */
  57.  
  58. /*
  59.  * The following hokiness with global variables is so that on
  60.  * receipt of an interrupt signal, the partial message can be salted
  61.  * away on dead.letter.  The output file must be available to flush,
  62.  * and the input to read.  Several open files could be saved all through
  63.  * Mail if stdio allowed simultaneous read/write access.
  64.  */
  65.  
  66. static    int    (*savesig)();        /* Previous SIGINT value */
  67. static    int    (*savehup)();        /* Previous SIGHUP value */
  68. # ifdef VMUNIX
  69. static    int    (*savecont)();        /* Previous SIGCONT value */
  70. # endif VMUNIX
  71. static    FILE    *newi;            /* File for saving away */
  72. static    FILE    *newo;            /* Output side of same */
  73. static    int    hf;            /* Ignore interrups */
  74. static    int    hadintr;        /* Have seen one SIGINT so far */
  75.  
  76. static    jmp_buf    coljmp;            /* To get back to work */
  77.  
  78. FILE *
  79. collect(hp)
  80.     struct header *hp;
  81. {
  82.     FILE *ibuf, *fbuf, *obuf;
  83.     int lc, cc, escape, collrub(), intack(), collcont(), eof;
  84.     register int c, t;
  85.     char linebuf[LINESIZE], *cp;
  86.     extern char tempMail[];
  87. #ifndef V4_2BSD
  88. #ifndef V4_1BSD
  89.     extern collintsig(), collhupsig();
  90. #endif  V4_1BSD
  91. #endif  V4_2BSD
  92.     char getsub;
  93.  
  94.     noreset++;
  95.     ibuf = obuf = NULL;
  96.     if (value("ignore") != NOSTR)
  97.         hf = 1;
  98.     else
  99.         hf = 0;
  100.     hadintr = 0;
  101. # ifdef V4_2BSD
  102.     if ((savesig = sigset(SIGINT, SIG_IGN)) != SIG_IGN)
  103.         sigset(SIGINT, hf ? intack : collrub), sigblock(sigmask(SIGINT)
  104. );
  105.     if ((savehup = sigset(SIGHUP, SIG_IGN)) != SIG_IGN)
  106.         sigset(SIGHUP, collrub), sigblock(sigmask(SIGHUP));
  107.     savecont = sigset(SIGCONT, collcont);
  108. # else V4_2BSD
  109. # ifdef V4_1BSD
  110.     if ((savesig = sigset(SIGINT, SIG_IGN)) != SIG_IGN)
  111.         sigset(SIGINT, hf ? intack : collrub), sighold(SIGINT);
  112.     if ((savesig = sigset(SIGHUP, SIG_IGN)) != SIG_IGN)
  113.         sigset(SIGHUP, hf ? intack : collrub), sighold(SIGHUP);
  114.     savecont = sigset(SIGCONT, collcont);
  115. # else
  116.     savesig = signal(SIGINT, SIG_IGN);
  117.     savehup = signal(SIGHUP, SIG_IGN);
  118. # endif V4_1BSD
  119. # endif V4_2BSD
  120.     newi = NULL;
  121.     newo = NULL;
  122.     if ((obuf = fopen(tempMail, "w")) == NULL) {
  123.         perror(tempMail);
  124.         goto err;
  125.     }
  126.     newo = obuf;
  127.     if ((ibuf = fopen(tempMail, "r")) == NULL) {
  128.         perror(tempMail);
  129.         newo = NULL;
  130.         fclose(obuf);
  131.         goto err;
  132.     }
  133.     newi = ibuf;
  134.     remove(tempMail);
  135.  
  136.     /*
  137.      * If we are going to prompt for a subject,
  138.      * refrain from printing a newline after
  139.      * the headers (since some people mind).
  140.      */
  141.  
  142.     t = GTO|GSUBJECT|GCC|GNL;
  143.     getsub = 0;
  144.     if (intty && sflag == NOSTR && hp->h_subject == NOSTR && value("ask"))
  145.         t &= ~GNL, getsub++;
  146.     if (hp->h_seq != 0) {
  147.         puthead(hp, stdout, t);
  148.         fflush(stdout);
  149.     }
  150.     escape = ESCAPE;
  151.     if ((cp = value("escape")) != NOSTR)
  152.         escape = *cp;
  153.     eof = 0;
  154.     for (;;) {
  155. # ifdef V4_2BSD
  156.         int omask = sigblock(0) &~ (sigmask(SIGINT)|sigmask(SIGHUP));
  157. # endif V4_2BSD
  158.  
  159.         setjmp(coljmp);
  160. # ifdef V4_2BSD
  161.         sigsetmask(omask);
  162. # else  V4_2BSD
  163. # ifdef V4_1BSD
  164.         if (savesig != SIG_IGN)
  165.             sigrelse(SIGINT);
  166.         if (savehup != SIG_IGN)
  167.             sigrelse(SIGHUP);
  168. # else  V4_1BSD
  169.         if (savesig != SIG_IGN)
  170.             signal(SIGINT, hf ? intack : collintsig);
  171.         if (savehup != SIG_IGN)
  172.             signal(SIGHUP, collhupsig);
  173. # endif V4_1BSD
  174. # endif V4_2BSD
  175.         fflush(stdout);
  176.         if (getsub) {
  177.             grabh(hp, GSUBJECT);
  178.             getsub = 0;
  179.             continue;
  180.         }
  181.         if (readline(stdin, linebuf) <= 0) {
  182.             if (intty && value("ignoreeof") != NOSTR) {
  183.                 if (++eof > 35)
  184.                     break;
  185.                 printf("Use \".\" to terminate letter\n",
  186.                     escape);
  187.                 continue;
  188.             }
  189.             break;
  190.         }
  191.         eof = 0;
  192.         hadintr = 0;
  193.         if (intty && equal(".", linebuf) &&
  194.             (value("dot") != NOSTR || value("ignoreeof") != NOSTR))
  195.             break;
  196.         if (linebuf[0] != escape || rflag != NOSTR) {
  197.             if ((t = putline(obuf, linebuf)) < 0)
  198.                 goto err;
  199.             continue;
  200.         }
  201.         c = linebuf[1];
  202.         switch (c) {
  203.         default:
  204.             /*
  205.              * On double escape, just send the single one.
  206.              * Otherwise, it's an error.
  207.              */
  208.  
  209.             if (c == escape) {
  210.                 if (putline(obuf, &linebuf[1]) < 0)
  211.                     goto err;
  212.                 else
  213.                     break;
  214.             }
  215.             printf("Unknown tilde escape.\n");
  216.             break;
  217.  
  218.         case 'C':
  219.             /*
  220.              * Dump core.
  221.              */
  222.  
  223.             core();
  224.             break;
  225.  
  226.         case '!':
  227.             /*
  228.              * Shell escape, send the balance of the
  229.              * line to sh -c.
  230.              */
  231.  
  232.             shell(&linebuf[2]);
  233.             break;
  234.  
  235.         case ':':
  236.         case '_':
  237.             /*
  238.              * Escape to command mode, but be nice!
  239.              */
  240.  
  241.             execute(&linebuf[2], 1);
  242.             printf("(continue)\n");
  243.             break;
  244.  
  245.         case '.':
  246.             /*
  247.              * Simulate end of file on input.
  248.              */
  249.             goto eofl;
  250.  
  251.         case 'q':
  252.         case 'Q':
  253.             /*
  254.              * Force a quit of sending mail.
  255.              * Act like an interrupt happened.
  256.              */
  257.  
  258.             hadintr++;
  259.             collrub(SIGINT);
  260.             exit(1);
  261.  
  262.         case 'h':
  263.             /*
  264.              * Grab a bunch of headers.
  265.              */
  266.             if (!intty || !outtty) {
  267.                 printf("~h: no can do!?\n");
  268.                 break;
  269.             }
  270.             grabh(hp, GTO|GSUBJECT|GCC|GBCC);
  271.             printf("(continue)\n");
  272.             break;
  273.  
  274.         case 't':
  275.             /*
  276.              * Add to the To list.
  277.              */
  278.  
  279.             hp->h_to = addto(hp->h_to,
  280.                 detract(elide(extract(&linebuf[2], GTO)),
  281.                     GTO));
  282.             hp->h_seq++;
  283.             break;
  284.  
  285.         case 's':
  286.             /*
  287.              * Set the Subject list.
  288.              */
  289.  
  290.             cp = &linebuf[2];
  291.             while (any(*cp, " \t"))
  292.                 cp++;
  293.             hp->h_subject = savestr(cp);
  294.             hp->h_seq++;
  295.             break;
  296.  
  297.         case 'c':
  298.             /*
  299.              * Add to the CC list.
  300.              */
  301.  
  302.             hp->h_cc = addto(hp->h_cc,
  303.                 detract(elide(extract(&linebuf[2], GCC)),
  304.                     GCC));
  305.             hp->h_seq++;
  306.             break;
  307.  
  308.         case 'b':
  309.             /*
  310.              * Add stuff to blind carbon copies list.
  311.              */
  312.             hp->h_bcc = addto(hp->h_bcc,
  313.                 detract(elide(extract(&linebuf[2],
  314.                               GBCC)),GBCC));
  315.             hp->h_seq++;
  316.             break;
  317.  
  318.         case 'd':
  319.             copy(deadlettername, &linebuf[2]);
  320.             /* fall into . . . */
  321.  
  322.         case 'r':
  323.             /*
  324.              * Invoke a file:
  325.              * Search for the file name,
  326.              * then open it and copy the contents to obuf.
  327.              */
  328.  
  329.             cp = &linebuf[2];
  330.             while (any(*cp, " \t"))
  331.                 cp++;
  332.             if (*cp == '\0') {
  333.                 printf("Interpolate what file?\n");
  334.                 break;
  335.             }
  336.             cp = expand(cp);
  337.             if (cp == NOSTR)
  338.                 break;
  339.             if (isdir(cp)) {
  340.                 printf("%s: directory\n");
  341.                 break;
  342.             }
  343.             if ((fbuf = fopen(cp, "r")) == NULL) {
  344.                 perror(cp);
  345.                 break;
  346.             }
  347.             printf("\"%s\" ", cp);
  348.             fflush(stdout);
  349.             lc = 0;
  350.             cc = 0;
  351.             while (readline(fbuf, linebuf) > 0) {
  352.                 lc++;
  353.                 if ((t = putline(obuf, linebuf)) < 0) {
  354.                     fclose(fbuf);
  355.                     goto err;
  356.                 }
  357.                 cc += t;
  358.             }
  359.             fclose(fbuf);
  360.             printf("%d/%d\n", lc, cc);
  361.             break;
  362.  
  363.         case 'w':
  364.             /*
  365.              * Write the message on a file.
  366.              */
  367.  
  368.             cp = &linebuf[2];
  369.             while (any(*cp, " \t"))
  370.                 cp++;
  371.             if (*cp == '\0') {
  372.                 fprintf(stderr, "Write what file!?\n");
  373.                 break;
  374.             }
  375.             if ((cp = expand(cp)) == NOSTR)
  376.                 break;
  377.             fflush(obuf);
  378.             rewind(ibuf);
  379.             exwrite(cp, ibuf, 1);
  380.             break;
  381.  
  382.         case 'm':
  383.         case 'f':
  384.             /*
  385.              * Interpolate the named messages, if we
  386.              * are in receiving mail mode.  Does the
  387.              * standard list processing garbage.
  388.              * If ~f is given, we don't shift over.
  389.              */
  390.  
  391.             if (!rcvmode) {
  392.                 printf("No messages to send from!?!\n");
  393.                 break;
  394.             }
  395.             cp = &linebuf[2];
  396.             while (any(*cp, " \t"))
  397.                 cp++;
  398.             if (forward(cp, obuf, c) < 0)
  399.                 goto err;
  400.             printf("(continue)\n");
  401.             break;
  402.  
  403.         case '?':
  404.             if ((fbuf = fopen(THELPFILE, "r")) == NULL) {
  405.                 perror(THELPFILE);
  406.                 break;
  407.             }
  408.             t = getc(fbuf);
  409.             while (t != -1) {
  410.                 putchar(t);
  411.                 t = getc(fbuf);
  412.             }
  413.             fclose(fbuf);
  414.             break;
  415.  
  416.         case 'p':
  417.             /*
  418.              * Print out the current state of the
  419.              * message without altering anything.
  420.              */
  421.  
  422.             fflush(obuf);
  423.             rewind(ibuf);
  424.             printf("-------\nMessage contains:\n");
  425.             puthead(hp, stdout, GTO|GSUBJECT|GCC|GBCC|GNL);
  426.             t = getc(ibuf);
  427.             while (t != EOF) {
  428.                 putchar(t);
  429.                 t = getc(ibuf);
  430.             }
  431.             printf("(continue)\n");
  432.             break;
  433.  
  434.         case '^':
  435.         case '|':
  436.             /*
  437.              * Pipe message through command.
  438.              * Collect output as new message.
  439.              */
  440.  
  441.             obuf = mespipe(ibuf, obuf, &linebuf[2]);
  442.             newo = obuf;
  443.             ibuf = newi;
  444.             newi = ibuf;
  445.             printf("(continue)\n");
  446.             break;
  447.  
  448.         case 'v':
  449.         case 'e':
  450.             /*
  451.              * Edit the current message.
  452.              * 'e' means to use EDITOR
  453.              * 'v' means to use VISUAL
  454.              */
  455.  
  456.             if ((obuf = mesedit(ibuf, obuf, c)) == NULL)
  457.                 goto err;
  458.             newo = obuf;
  459.             ibuf = newi;
  460.             printf("(continue)\n");
  461.             break;
  462.         }
  463.     }
  464. eofl:
  465.     fclose(obuf);
  466.     rewind(ibuf);
  467.     sigset(SIGINT, savesig);
  468.     sigset(SIGHUP, savehup);
  469. # ifdef VMUNIX
  470.     sigset(SIGCONT, savecont);
  471. # ifdef V4_2BSD
  472.     sigsetmask(0);
  473. # endif V4_2BSD
  474. # endif VMUNIX
  475.     noreset = 0;
  476.     return(ibuf);
  477.  
  478. err:
  479.     if (ibuf != NULL)
  480.         fclose(ibuf);
  481.     if (obuf != NULL)
  482.         fclose(obuf);
  483.     sigset(SIGINT, savesig);
  484.     sigset(SIGHUP, savehup);
  485. # ifdef VMUNIX
  486.     sigset(SIGCONT, savecont);
  487. # ifdef V4_2BSD
  488.     sigsetmask(0);
  489. # endif V4_2BSD
  490. # endif VMUNIX
  491.     noreset = 0;
  492.     return(NULL);
  493. }
  494.  
  495. #ifdef NOT_USED
  496. /*
  497.  * Non destructively interrogate the value of the given signal.
  498.  */
  499.  
  500. psig(n)
  501. {
  502.     register (*wassig)();
  503.  
  504.     wassig = sigset(n, SIG_IGN);
  505.     sigset(n, wassig);
  506.     return((int) wassig);
  507. }
  508. #endif NOT_USED
  509.  
  510. /*
  511.  * Write a file, ex-like if f set.
  512.  */
  513.  
  514. exwrite(name, ibuf, f)
  515.     char name[];
  516.     FILE *ibuf;
  517. {
  518.     register FILE *of;
  519.     register int c;
  520.     long cc;
  521.     int lc;
  522.     struct stat junk;
  523.  
  524.     if (f) {
  525.         printf("\"%s\" ", name);
  526.         fflush(stdout);
  527.     }
  528.     if (stat(name, &junk) >= 0 && (junk.st_mode & S_IFMT) == S_IFREG) {
  529.         if (!f)
  530.             fprintf(stderr, "%s: ", name);
  531.         fprintf(stderr, "File exists\n", name);
  532.         return;
  533.     }
  534.     if ((of = fopen(name, "w")) == NULL) {
  535.         perror(NOSTR);
  536.         return;
  537.     }
  538.     lc = 0;
  539.     cc = 0;
  540.     while ((c = getc(ibuf)) != EOF) {
  541.         cc++;
  542.         if (c == '\n')
  543.             lc++;
  544.         putc(c, of);
  545.         if (ferror(of)) {
  546.             perror(name);
  547.             fclose(of);
  548.             return;
  549.         }
  550.     }
  551.     fclose(of);
  552.     printf("%d/%ld\n", lc, cc);
  553.     fflush(stdout);
  554. }
  555.  
  556. /*
  557.  * Edit the message being collected on ibuf and obuf.
  558.  * Write the message out onto some poorly-named temp file
  559.  * and point an editor at it.
  560.  *
  561.  * On return, make the edit file the new temp file.
  562.  */
  563.  
  564. FILE *
  565. mesedit(ibuf, obuf, c)
  566.     FILE *ibuf, *obuf;
  567. {
  568.     int pid, s;
  569.     FILE *fbuf;
  570.     register int t;
  571.     int (*sig)(), (*scont)(), signull();
  572.     struct stat sbuf;
  573.     extern char tempMail[], tempEdit[];
  574.     register char *ed;
  575.  
  576.     sig = sigset(SIGINT, SIG_IGN);
  577. # ifdef VMUNIX
  578.     scont = sigset(SIGCONT, signull);
  579. # endif VMUNIX
  580.     if (stat(tempEdit, &sbuf) >= 0) {
  581.         printf("%s: file exists\n", tempEdit);
  582.         goto out;
  583.     }
  584.     close(creat(tempEdit, 0600));
  585.     if ((fbuf = fopen(tempEdit, "w")) == NULL) {
  586.         perror(tempEdit);
  587.         goto out;
  588.     }
  589.     fflush(obuf);
  590.     rewind(ibuf);
  591.     t = getc(ibuf);
  592.     while (t != EOF) {
  593.         putc(t, fbuf);
  594.         t = getc(ibuf);
  595.     }
  596.     fflush(fbuf);
  597.     if (ferror(fbuf)) {
  598.         perror(tempEdit);
  599.         remove(tempEdit);
  600.         goto fix;
  601.     }
  602.     fclose(fbuf);
  603.     if ((ed = value(c == 'e' ? "EDITOR" : "VISUAL")) == NOSTR)
  604.         ed = c == 'e' ? EDITOR : VISUAL;
  605.     pid = vfork();
  606.     if (pid == 0) {
  607.         sigchild();
  608.         if (sig != SIG_IGN)
  609.             sigsys(SIGINT, SIG_DFL);
  610.         execl(ed, ed, tempEdit, 0);
  611.         perror(ed);
  612.         _exit(1);
  613.     }
  614.     if (pid == -1) {
  615.         perror("fork");
  616.         remove(tempEdit);
  617.         goto out;
  618.     }
  619.     while (wait(&s) != pid)
  620.         ;
  621.     if ((s & 0377) != 0) {
  622.         printf("Fatal error in \"%s\"\n", ed);
  623.         remove(tempEdit);
  624.         goto out;
  625.     }
  626.  
  627.     /*
  628.      * Now switch to new file.
  629.      */
  630.  
  631.     if ((fbuf = fopen(tempEdit, "a")) == NULL) {
  632.         perror(tempEdit);
  633.         remove(tempEdit);
  634.         goto out;
  635.     }
  636.     if ((ibuf = fopen(tempEdit, "r")) == NULL) {
  637.         perror(tempEdit);
  638.         fclose(fbuf);
  639.         remove(tempEdit);
  640.         goto out;
  641.     }
  642.     remove(tempEdit);
  643.     fclose(obuf);
  644.     fclose(newi);
  645.     obuf = fbuf;
  646.     goto out;
  647. fix:
  648.     perror(tempEdit);
  649. out:
  650. # ifdef VMUNIX
  651.     sigset(SIGCONT, scont);
  652. # endif VMUNIX
  653.     sigset(SIGINT, sig);
  654.     newi = ibuf;
  655.     return(obuf);
  656. }
  657.  
  658. /*
  659.  * Pipe the message through the command.
  660.  * Old message is on stdin of command;
  661.  * New message collected from stdout.
  662.  * Sh -c must return 0 to accept the new message.
  663.  */
  664.  
  665. FILE *
  666. mespipe(ibuf, obuf, cmd)
  667.     FILE *ibuf, *obuf;
  668.     char cmd[];
  669. {
  670.     register FILE *ni, *no;
  671.     int pid, s;
  672.     int (*savsig)();
  673.     char *Shell;
  674.  
  675.     newi = ibuf;
  676.     if ((no = fopen(tempEdit, "w")) == NULL) {
  677.         perror(tempEdit);
  678.         return(obuf);
  679.     }
  680.     if ((ni = fopen(tempEdit, "r")) == NULL) {
  681.         perror(tempEdit);
  682.         fclose(no);
  683.         remove(tempEdit);
  684.         return(obuf);
  685.     }
  686.     remove(tempEdit);
  687.     savsig = sigset(SIGINT, SIG_IGN);
  688.     fflush(obuf);
  689.     rewind(ibuf);
  690.     if ((Shell = value("SHELL")) == NULL)
  691.         Shell = "/bin/sh";
  692.     if ((pid = vfork()) == -1) {
  693.         perror("fork");
  694.         goto err;
  695.     }
  696.     if (pid == 0) {
  697.         /*
  698.          * stdin = current message.
  699.          * stdout = new message.
  700.          */
  701.  
  702.         sigchild();
  703.         close(0);
  704.         dup(fileno(ibuf));
  705.         close(1);
  706.         dup(fileno(no));
  707.         for (s = 4; s < 15; s++)
  708.             close(s);
  709.         execl(Shell, Shell, "-c", cmd, 0);
  710.         perror(Shell);
  711.         _exit(1);
  712.     }
  713.     while (wait(&s) != pid)
  714.         ;
  715.     if (s != 0 || pid == -1) {
  716.         fprintf(stderr, "\"%s\" failed!?\n", cmd);
  717.         goto err;
  718.     }
  719.     if (fsize(ni) == 0) {
  720.         fprintf(stderr, "No bytes from \"%s\" !?\n", cmd);
  721.         goto err;
  722.     }
  723.  
  724.     /*
  725.      * Take new files.
  726.      */
  727.  
  728.     newi = ni;
  729.     fclose(ibuf);
  730.     fclose(obuf);
  731.     sigset(SIGINT, savsig);
  732.     return(no);
  733.  
  734. err:
  735.     fclose(no);
  736.     fclose(ni);
  737.     sigset(SIGINT, savsig);
  738.     return(obuf);
  739. }
  740.  
  741. /*
  742.  * Interpolate the named messages into the current
  743.  * message, preceding each line with a tab.
  744.  * Return a count of the number of characters now in
  745.  * the message, or -1 if an error is encountered writing
  746.  * the message temporary.  The flag argument is 'm' if we
  747.  * should shift over and 'f' if not.
  748.  */
  749. forward(ms, obuf, f)
  750.     char ms[];
  751.     FILE *obuf;
  752. {
  753.     register int *msgvec, *ip;
  754.     extern char tempMail[];
  755.  
  756.     msgvec = (int *) salloc((msgCount+1) * sizeof *msgvec);
  757.     if (msgvec == (int *) NOSTR)
  758.         return(0);
  759.     if (getmsglist(ms, msgvec, 0) < 0)
  760.         return(0);
  761.     if (*msgvec == NULL) {
  762.         *msgvec = first(0, MMNORM);
  763.         if (*msgvec == NULL) {
  764.             printf("No appropriate messages\n");
  765.             return(0);
  766.         }
  767.         msgvec[1] = NULL;
  768.     }
  769.     printf("Interpolating:");
  770.     for (ip = msgvec; *ip != NULL; ip++) {
  771.         touch(*ip);
  772.         printf(" %d", *ip);
  773.         if (f == 'm') {
  774.             if (transmit(&message[*ip-1], obuf) < 0L) {
  775.                 perror(tempMail);
  776.                 return(-1);
  777.             }
  778.         } else
  779.             if (send(&message[*ip-1], obuf, 0, 0) < 0) {
  780.                 perror(tempMail);
  781.                 return(-1);
  782.             }
  783.     }
  784.     printf("\n");
  785.     return(0);
  786. }
  787.  
  788. /*
  789.  * Send message described by the passed pointer to the
  790.  * passed output buffer.  Insert a tab in front of each
  791.  * line.  Return a count of the characters sent, or -1
  792.  * on error.
  793.  */
  794.  
  795. long
  796. transmit(mailp, obuf)
  797.     struct message *mailp;
  798.     FILE *obuf;
  799. {
  800.     register struct message *mp;
  801.     register int ch;
  802.     long c, n;
  803.     int bol;
  804.     FILE *ibuf;
  805.  
  806.     mp = mailp;
  807.     ibuf = setinput(mp);
  808.     c = mp->m_size;
  809.     n = c;
  810.     bol = 1;
  811.     while (c-- > 0L) {
  812.         if (bol) {
  813.             bol = 0;
  814.             putc('\t', obuf);
  815.             n++;
  816.             if (ferror(obuf)) {
  817.                 perror("/tmp");
  818.                 return(-1L);
  819.             }
  820.         }
  821.         ch = getc(ibuf);
  822.         if (ch == '\n')
  823.             bol++;
  824.         putc(ch, obuf);
  825.         if (ferror(obuf)) {
  826.             perror("/tmp");
  827.             return(-1L);
  828.         }
  829.     }
  830.     return(n);
  831. }
  832.  
  833. /*
  834.  * Print (continue) when continued after ^Z.
  835.  */
  836. collcont()
  837. {
  838.  
  839.     printf("(continue)\n");
  840.     fflush(stdout);
  841. }
  842.  
  843. /*
  844.  * On interrupt, go here to save the partial
  845.  * message on ~/dead.letter.
  846.  * Then restore signals and execute the normal
  847.  * signal routine.  We only come here if signals
  848.  * were previously set anyway.
  849.  */
  850.  
  851. # ifndef VMUNIX
  852. collintsig()
  853. {
  854.     signal(SIGINT, SIG_IGN);
  855.     collrub(SIGINT);
  856. }
  857.  
  858. collhupsig()
  859. {
  860.     signal(SIGHUP, SIG_IGN);
  861.     collrub(SIGHUP);
  862. }
  863. # endif VMUNIX
  864.  
  865. collrub(s)
  866. {
  867.     register FILE *dbuf;
  868.     register int c;
  869.  
  870.     if (s == SIGINT && hadintr == 0) {
  871.         hadintr++;
  872.         fflush(stdout);
  873.         fprintf(stderr, "\n(Interrupt -- one more to kill letter)\n");
  874.         longjmp(coljmp, 1);
  875.     }
  876.     fclose(newo);
  877.     rewind(newi);
  878.     if (s == SIGINT && value("nosave") != NOSTR || fsize(newi) == 0)
  879.         goto done;
  880.     if ((dbuf = fopen(deadlettername, "w")) == NULL)
  881.         goto done;
  882.     chmod(deadlettername, 0600);
  883.     while ((c = getc(newi)) != EOF)
  884.         putc(c, dbuf);
  885.     fclose(dbuf);
  886.  
  887. done:
  888.     fclose(newi);
  889.     sigset(SIGINT, savesig);
  890.     sigset(SIGHUP, savehup);
  891. # ifdef VMUNIX
  892.     sigset(SIGCONT, savecont);
  893. # endif VMUNIX
  894.     if (rcvmode) {
  895.         if (s == SIGHUP)
  896.             hangup();
  897.         else
  898. #ifndef VMUNIX
  899.                 stop(s);
  900. #else   VMUNIX
  901.             stop();
  902. #endif  VMUNIX
  903.     }
  904.     else
  905.         exit(1);
  906. }
  907.  
  908. /*
  909.  * Acknowledge an interrupt signal from the tty by typing an @
  910.  */
  911.  
  912. intack()
  913. {
  914.     
  915.     puts("@");
  916.     fflush(stdout);
  917.     clearerr(stdin);
  918. }
  919.  
  920. /*
  921.  * Add a string to the end of a header entry field.
  922.  */
  923.  
  924. char *
  925. addto(hfld, news)
  926.     char hfld[], news[];
  927. {
  928.     register char *cp, *cp2, *linebuf;
  929.     register int comma;
  930.  
  931.     if (hfld == NOSTR)
  932.         hfld = "";
  933.     if (*news == '\0')
  934.         return(hfld);
  935.     linebuf = salloc(strlen(hfld) + strlen(news) + 3); /* maybe comma */
  936.     for (cp = hfld; any(*cp, " \t"); cp++)
  937.         ;
  938.     comma = *cp ? 1 : 0;
  939.     for (cp2 = linebuf; *cp;)
  940.         *cp2++ = *cp++;
  941.     if (comma)
  942.         *cp2++ = ',';    /* here's the comma */
  943.     *cp2++ = ' ';
  944.     for (cp = news; any(*cp, " \t"); cp++)
  945.         ;
  946.     while (*cp != '\0')
  947.         *cp2++ = *cp++;
  948.     *cp2 = '\0';
  949.     return(linebuf);
  950. }
  951.